package com.finupgroup.postloan.generator.engine;

import com.baomidou.mybatisplus.toolkit.StringUtils;
import com.finupgroup.postloan.generator.config.ConstVal;
import com.finupgroup.postloan.generator.config.GlobalConfig;
import com.finupgroup.postloan.generator.config.TemplateInfo;
import com.finupgroup.postloan.generator.config.builder.ConfigBuilder;
import com.finupgroup.postloan.generator.config.po.TableInfo;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 模板引擎抽象类
 *
 * @author YueQingwei
 * @since 2018-04-10
 */
@Slf4j
public abstract class AbstractTemplateEngine {

    /**
     * 配置信息
     */
    private ConfigBuilder configBuilder;


    /**
     * <p>
     * 模板引擎初始化
     * </p>
     */
    public AbstractTemplateEngine init(ConfigBuilder configBuilder) {
        this.configBuilder = configBuilder;
        return this;
    }


    /**
     * <p>
     * 输出 java xml 文件
     * </p>
     */
    public AbstractTemplateEngine batchOutput() {
        try {
            List<TableInfo> tableInfoList = this.getConfigBuilder().getTableInfoList();
            for (TableInfo tableInfo : tableInfoList) {
                Map<String, Object> objectMap = this.getObjectMap(tableInfo);
                Map<String, String> pathInfo = this.getConfigBuilder().getPathInfo();

                TemplateInfo templateInfo = configBuilder.getTemplateInfo();

                // Entity.java
                String entityName = tableInfo.getEntityName();
                if (null != entityName && null != pathInfo.get(ConstVal.ENTITY_PATH)) {
                    String entityFile = pathInfo.get(ConstVal.ENTITY_PATH) + File.separator + entityName + this.suffixJava();
                    if (this.isCreate(entityFile)) {
                        this.writer(objectMap, this.templateFilePath(templateInfo.getEntity()), entityFile);
                    }
                }
                // Mapper.java
                if (null != tableInfo.getMapperName() && null != pathInfo.get(ConstVal.MAPPER_PATH)) {
                    String mapperFile = pathInfo.get(ConstVal.MAPPER_PATH) + File.separator + tableInfo.getMapperName() + this.suffixJava();
                    if (this.isCreate(mapperFile)) {
                        this.writer(objectMap, this.templateFilePath(templateInfo.getMapper()), mapperFile);
                    }
                }
                // Mapper.xml
                if (null != tableInfo.getXmlName() && null != pathInfo.get(ConstVal.XML_PATH)) {
                    String xmlFile = pathInfo.get(ConstVal.XML_PATH) + File.separator + tableInfo.getXmlName() + ConstVal.XML_SUFFIX;
                    if (this.isCreate(xmlFile)) {
                        this.writer(objectMap, this.templateFilePath(templateInfo.getXml()), xmlFile);
                    }
                }
                // Service.java
                if (null != tableInfo.getServiceName() && null != pathInfo.get(ConstVal.SERIVCE_PATH)) {
                    String serviceFile = pathInfo.get(ConstVal.SERIVCE_PATH) + File.separator + tableInfo.getServiceName() + this.suffixJava();
                    if (this.isCreate(serviceFile)) {
                        this.writer(objectMap, this.templateFilePath(templateInfo.getService()), serviceFile);
                    }
                }
                // ServiceImpl.java
                if (null != tableInfo.getServiceImplName() && null != pathInfo.get(ConstVal.SERVICEIMPL_PATH)) {
                    String implFile = pathInfo.get(ConstVal.SERVICEIMPL_PATH) + File.separator + tableInfo.getServiceImplName() + this.suffixJava();
                    if (this.isCreate(implFile)) {
                        this.writer(objectMap, this.templateFilePath(templateInfo.getServiceImpl()), implFile);
                    }
                }
                // Controller.java
                if (null != tableInfo.getControllerName() && null != pathInfo.get(ConstVal.CONTROLLER_PATH)) {
                    String controllerFile = pathInfo.get(ConstVal.CONTROLLER_PATH) + File.separator + tableInfo.getControllerName() + this.suffixJava();
                    if (this.isCreate(controllerFile)) {
                        this.writer(objectMap, this.templateFilePath(templateInfo.getController()), controllerFile);
                    }
                }
            }
        } catch (Exception e) {
            log.error("无法创建文件，请检查配置信息！", e);
        }
        return this;
    }


    /**
     * <p>
     * 将模板转化成为文件
     * </p>
     *
     * @param objectMap    渲染对象 MAP 信息
     * @param templatePath 模板文件
     * @param outputFile   文件生成的目录
     */
    public abstract void writer(Map<String, Object> objectMap, String templatePath, String outputFile) throws Exception;

    /**
     * <p>
     * 处理输出目录
     * </p>
     */
    public AbstractTemplateEngine mkdirs() {
        Map<String, String> pathInfo = this.getConfigBuilder().getPathInfo();
        for (Map.Entry<String, String> entry : pathInfo.entrySet()) {
            File dir = new File(entry.getValue());
            if (!dir.exists()) {
                boolean result = dir.mkdirs();
                if (result) {
                    log.info("创建目录： [" + entry.getValue() + "]");
                }
            }
        }
        return this;
    }

    /**
     * <p>
     * 渲染对象 MAP 信息
     * </p>
     *
     * @param tableInfo 表信息对象
     * @return
     */
    public Map<String, Object> getObjectMap(TableInfo tableInfo) {
        Map<String, Object> objectMap = new HashMap<>();
        ConfigBuilder config = this.getConfigBuilder();
        objectMap.put("package", config.getPackageInfo());
        GlobalConfig globalConfig = config.getGlobalConfig();
        objectMap.put("author", globalConfig.getAuthor());
        objectMap.put("logicDeleteFieldName", config.getStrategyConfig().getLogicDeleteFieldName());
        objectMap.put("versionFieldName", config.getStrategyConfig().getVersionFieldName());
        objectMap.put("date", LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE));
        objectMap.put("table", tableInfo);
        objectMap.put("baseResultMap", globalConfig.isBaseResultMap());
        objectMap.put("baseColumnList", globalConfig.isBaseColumnList());
        objectMap.put("entity", tableInfo.getEntityName());
        objectMap.put("entityColumnConstant", config.getStrategyConfig().isEntityColumnConstant());
        objectMap.put("entityLombokModel", config.getStrategyConfig().isEntityLombokModel());
        objectMap.put("entityBooleanColumnRemoveIsPrefix", config.getStrategyConfig().isEntityBooleanColumnRemoveIsPrefix());
        objectMap.put("superEntityClass", getSuperClassName(config.getSuperEntityClass()));
        objectMap.put("superMapperClassPackage", config.getSuperMapperClass());
        objectMap.put("superMapperClass", getSuperClassName(config.getSuperMapperClass()));
        objectMap.put("superServiceClassPackage", config.getSuperServiceClass());
        objectMap.put("superServiceClass", getSuperClassName(config.getSuperServiceClass()));
        objectMap.put("superServiceImplClassPackage", config.getSuperServiceImplClass());
        objectMap.put("superServiceImplClass", getSuperClassName(config.getSuperServiceImplClass()));
        objectMap.put("superControllerClassPackage", config.getSuperControllerClass());
        objectMap.put("superControllerClass", getSuperClassName(config.getSuperControllerClass()));
        return objectMap;
    }


    /**
     * 获取类名
     *
     * @param classPath
     * @return
     */
    private static String getSuperClassName(String classPath) {
        if (StringUtils.isEmpty(classPath)) {
            return null;
        }
        return classPath.substring(classPath.lastIndexOf(".") + 1);
    }


    /**
     * <p>
     * 模板真实文件路径
     * </p>
     *
     * @param filePath 文件路径
     * @return
     */
    public abstract String templateFilePath(String filePath);


    /**
     * 检测文件是否存在
     *
     * @return 是否
     */
    protected boolean isCreate(String filePath) {
        File file = new File(filePath);
        boolean exist = file.exists();
        if (!exist) {
            this.mkdirs(file.getParentFile());
        }
        return !exist;
    }

    protected void mkdirs(File file) {
        if (null != file) {
            if (file.getParentFile().exists()) {
                file.mkdir();
            } else {
                mkdirs(file.getParentFile());
                file.mkdir();
            }
        }
    }


    /**
     * 文件后缀
     */
    protected String suffixJava() {
        return ConstVal.JAVA_SUFFIX;
    }


    public ConfigBuilder getConfigBuilder() {
        return configBuilder;
    }
}
